package auth

import (
	"errors"
	"time"

	"awesomeProject/internal/model"
	"github.com/golang-jwt/jwt/v5"
)

// Claims JWT声明结构
type Claims struct {
	UserID   uint   `json:"user_id"`
	Username string `json:"username"`
	Role     string `json:"role"`
	jwt.RegisteredClaims
}

// JWTManager JWT管理器
type JWTManager struct {
	secretKey     string
	tokenDuration time.Duration
}

// NewJWTManager 创建JWT管理器实例
func NewJWTManager(secretKey string, tokenDuration time.Duration) *JWTManager {
	return &JWTManager{
		secretKey:     secretKey,
		tokenDuration: tokenDuration,
	}
}

// GenerateToken 生成JWT token
func (manager *JWTManager) GenerateToken(user *model.User) (string, error) {
	// 设置token过期时间
	now := time.Now()
	expiresAt := now.Add(manager.tokenDuration)

	// 创建声明
	claims := &Claims{
		UserID:   user.ID,
		Username: user.Username,
		Role:     user.Role,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(expiresAt),
			IssuedAt:  jwt.NewNumericDate(now),
			NotBefore: jwt.NewNumericDate(now),
			Issuer:    "awesomeProject",
			Subject:   user.Username,
		},
	}

	// 创建token
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// 签名token
	tokenString, err := token.SignedString([]byte(manager.secretKey))
	if err != nil {
		return "", err
	}

	return tokenString, nil
}

// VerifyToken 验证JWT token
func (manager *JWTManager) VerifyToken(tokenString string) (*Claims, error) {
	// 解析token
	token, err := jwt.ParseWithClaims(
		tokenString,
		&Claims{},
		func(token *jwt.Token) (interface{}, error) {
			// 验证签名方法
			if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
				return nil, errors.New("unexpected signing method")
			}
			return []byte(manager.secretKey), nil
		},
	)

	if err != nil {
		return nil, err
	}

	// 验证token有效性
	if !token.Valid {
		return nil, errors.New("invalid token")
	}

	// 提取声明
	claims, ok := token.Claims.(*Claims)
	if !ok {
		return nil, errors.New("invalid token claims")
	}

	return claims, nil
}

// RefreshToken 刷新token
func (manager *JWTManager) RefreshToken(tokenString string) (string, error) {
	// 验证当前token
	claims, err := manager.VerifyToken(tokenString)
	if err != nil {
		return "", err
	}

	// 检查token是否即将过期（在30分钟内过期才允许刷新）
	now := time.Now()
	if claims.ExpiresAt.Time.Sub(now) > 30*time.Minute {
		return "", errors.New("token is not eligible for refresh")
	}

	// 创建新的声明
	newClaims := &Claims{
		UserID:   claims.UserID,
		Username: claims.Username,
		Role:     claims.Role,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(now.Add(manager.tokenDuration)),
			IssuedAt:  jwt.NewNumericDate(now),
			NotBefore: jwt.NewNumericDate(now),
			Issuer:    "awesomeProject",
			Subject:   claims.Username,
		},
	}

	// 生成新token
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, newClaims)
	return token.SignedString([]byte(manager.secretKey))
}

// ExtractUserID 从token中提取用户ID
func (manager *JWTManager) ExtractUserID(tokenString string) (uint, error) {
	claims, err := manager.VerifyToken(tokenString)
	if err != nil {
		return 0, err
	}
	return claims.UserID, nil
}

// ExtractUsername 从token中提取用户名
func (manager *JWTManager) ExtractUsername(tokenString string) (string, error) {
	claims, err := manager.VerifyToken(tokenString)
	if err != nil {
		return "", err
	}
	return claims.Username, nil
}

// ExtractRole 从token中提取用户角色
func (manager *JWTManager) ExtractRole(tokenString string) (string, error) {
	claims, err := manager.VerifyToken(tokenString)
	if err != nil {
		return "", err
	}
	return claims.Role, nil
}

